package aop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Aspect 告诉 Spring 当前类是一个切面类
 * Spring 自己没有定义关于切面相关的注解，而是使用来自 org.aspectj 这个 Jar 包里的注解（但是没有用它的技术解析，这点需要明白）
 * org.aspectj.lang.annotation 还有很多其余的注解，但是这里列出 Spring 只支持的注解如下：
 * @Aspect、@Before、@After、@AfterReturning、@AfterThrowing、@Around 其余的注解 Spring 都是不予解析的（由 AspectJ 内部技术去解析）
 * https://blog.csdn.net/f641385712/article/details/83543270
 */
@Aspect
@Component
public class LogAspect {

    /**
     * 抽取公共的切入点表达式
     * 1、本类引用
     * 2、其他的切面引用
     */
    @Pointcut("execution(public int aop.service.MathCalculatorImpl.*(..))")
    public void pointCut() {
    }

    /**
     * @Before 在目标方法之前切入；切入点表达式（指定在哪个方法切入）
     */
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println("@Before-前置通知。参数列表是：{" + Arrays.asList(args) + "}");
    }

    @After("aop.aspect.LogAspect.pointCut()")
    public void logEnd(JoinPoint joinPoint) {
        System.out.println("@After-后置通知");
    }

    /**
     * JoinPoint一定要出现在参数表的第一位
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void logReturn(JoinPoint joinPoint, Object result) {
        System.out.println("@AfterReturning-正常返回后通知。运行结果：{" + result + "}");
    }

    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logException(JoinPoint joinPoint, Exception exception) {
        System.out.println("@AfterThrowing-方法执行异常通知。异常信息：{" + exception + "}");
    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object retValue = null;
        System.out.println("@Around-环绕通知之前。AAA");
        retValue = proceedingJoinPoint.proceed();
        System.out.println("@Around-环绕通知之后。BBB");
        return retValue;
    }
}